﻿using Blm.PgsqlDriver.Helpers;
using Blm.Utils.Extensions;
using Blm.Utils.Utility;
using Blm.VisionCloud.FrameWork.OSS;
using Language.Resource;
using Microsoft.Extensions.Localization;
using Newtonsoft.Json;
using Npgsql;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using VisionCloud.Core.Model.Enums;
using VisionCloud.Core.Model.Ms;
using VisionCloud.Domain.Common;
using VisionCloud.Domain.DtoModel.Applet.RequestDto;
using VisionCloud.Domain.DtoModel.Applet.ResponseDto;
using VisionCloud.Domain.DtoModel.Ms;
using VisionCloud.Domain.Repository.Interface.Ms;
using VisionCloud.Domain.Repository.Interface.Sys;
using VisionCloud.Domain.UnitOfWork;
using VisionCloud.Service.Ms;
using VisionCloud.Utility;

namespace VisionCloud.Service.Applet
{
    /// <summary>
    /// 诊断算法分析服务
    /// </summary>
    public class MeasureDataAnalysisService
    {
        /// <summary>
        /// 诊断服务API
        /// </summary>
        private readonly string baseUrl = ConfigHelper.GetValue<string>("MeasureDataAnalysisAPI");

        /// <summary>
        /// 请求超时时间
        /// </summary>
        private readonly int timeOut = 60;

        public MinioHelper MinioHelper { get; set; }

        public IUnitOfWork UnitOfWork { get; set; }

        public IStringLocalizer<ServiceResource> Localizer { get; set; }

        public IMsDiagnosticReportRepository MsDiagnosticReportRepository { get; set; }

        public Ms.ProjectService ProjectService { get; set; }

        public QualityAnalyzeService QualityAnalyzeService { get; set; }

        public ISysWxMessageRepository SysWxMessageRepository { get; set; }

        public IMsProjectStandardRepository MsProjectStandardRepository { get; set; }

        public StatisService StatisService { get; set; }

        public MeasureDataAnalysisService(MinioHelper MinioHelper)
        {
            this.MinioHelper = MinioHelper;
        }

        /// <summary>
        /// 文件服务器域名
        /// </summary>
        private static readonly string fileServer = ConfigHelper.GetValue<string>("FileServer");

        /// <summary>
        /// 生成诊断报告
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public async Task<ApiResult> WxGetQualityAnalysisReport(WxQualityAnalysisDto query)
        {
            #region 数据校验

            // 获取项目信息
            var project = await ProjectService.GetProjectInfo(query.ProjectId);
            if (project == null)
            {
                // 项目不存在
                throw new OperationException(Localizer["YB0064"].Value);
            }
            var buildingInfo = project.DetailsInfo.FirstOrDefault(
                x => x.Building == query.BuildingName);

            if (buildingInfo == null)
            {
                // 不存在的楼栋信息
                throw new OperationException(Localizer["YB0200"].Value);
            }
            if (!string.IsNullOrWhiteSpace(query.FloorName)
                && int.Parse(buildingInfo.Floor) < int.Parse(query.FloorName))
            {
                // 不存在的楼层信息
                throw new OperationException(Localizer["YB0467"].Value);
            }

            var projectStandard = await MsProjectStandardRepository.GetProjectStandardByName(
                OperatorProvider.Get().CompanyGuid, project.ProjectId, query.ProjectStage);

            if (projectStandard == null)
            {
                // 项目阶段不存在
                throw new OperationException(Localizer["YB0468"].Value);
            }
            query.ProjectName = project.Name;

            #endregion 数据校验

            // 获取质量分析数据
            var qualityData = await QualityAnalyzeService.WxGetQualityAnalysisData(query);

            #region 判断报告是否已存在

            var msDiagnosticReportRequest = new MsDiagnosticReportRequestDto()
            {
                ProjectId = project.ProjectId,
                BuildingName = query.BuildingName,
                ProjectStage = query.ProjectStage,
                CompanyId = OperatorProvider.Get().CompanyGuid,
                FloorName = query.FloorName,
                ProjectStandardId = projectStandard.ProjectStandardId,
                TaskProperty = query.TaskProperty,
                TaskType = query.TaskType
            };

            var report = await MsDiagnosticReportRepository.GetMsDiagnosticReport(msDiagnosticReportRequest);
            if (report != null)
            {
                qualityData.FileName = report.FileName;
                qualityData.Upd = "0";
                // 报告生成时间超过5min重新生成
                if (DateTime.Now.Subtract(report.LastUpdatedDate).TotalMinutes > 5)
                {
                    qualityData.Upd = "1";
                }
            }

            #endregion 判断报告是否已存在

            // 调用诊断算法接口
            var result = await MeasureDataAnalysis(qualityData);
            if (result == null || result.Code != 0)
            {
                // 诊断报告生成失败，请稍后再试
                throw new OperationException(Localizer["YB0471"].Value);
            }

            #region 保存业务数据和文件数据

            // 诊断报告重新生成
            if (qualityData.Upd == "1")
            {
                var queryReport = new MsDiagnosticReportRequestDto()
                {
                    ProjectId = query.ProjectId.ToGuid(),
                    ProjectNo = project.ProjectNo,
                    BuildingName = query.BuildingName,
                    FloorName = query.FloorName,
                    ProjectStage = projectStandard.Stage,
                    ProjectStandardId = projectStandard.ProjectStandardId,
                    SaveDir = qualityData.SaveDir,
                    FileName = qualityData.FileName,
                    TaskType = query.TaskType,
                    TaskProperty = query.TaskProperty
                };
                // 保存诊断报告数据
                var saveResult = await SaveDiagnosticReport(queryReport, (List<DiagnosticReport>)result.Data);
                if (saveResult.Code != AjaxCode.Success)
                {
                    return saveResult;
                }
                var reports = (List<MsDiagnosticReport>)saveResult.Result;
                report = reports?.FirstOrDefault(x => x.ObjectName.Contains("pdf"));
            }

            #endregion 保存业务数据和文件数据

            return ApiResult.Success().SetData(ToDiagnosticReportUrl(report?.ObjectName));
        }

        /// <summary>
        /// 数据诊断
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<MeasureDataAnalysisResponseDto> MeasureDataAnalysis(MeasureDataAnalysisDto request)
        {
            string json = JsonConvert.SerializeObject(request);
            string api = baseUrl + $"getrep";
            var headers = new Dictionary<string, string>();
            string body = string.Format("mdata={0}", json);
            string responseStr = string.Empty;
            Utility.Logger.Info($"请求参数{body}");
            using (var response = await HttpUtility.PostAsync(api, body, timeOut, headers, "application/x-www-form-urlencoded"))
            {
                try
                {
                    responseStr = await response.Content.ReadAsStringAsync();
                    var result = JsonConvert.DeserializeObject<MeasureDataAnalysisResponseDto>(responseStr);
                    if (result.Code != 0)
                    {
                        Utility.Logger.Info($"request code:{responseStr}[{response.StatusCode}]");
                        return result;
                    }
                    List<DiagnosticReport> fileList = result.Data as List<DiagnosticReport>;
                    if (fileList == null || fileList.Count == 0)
                    {
                        Utility.Logger.Info($"request code:{responseStr}[{response.StatusCode}]");
                        return result;
                    }

                    result.Data = JsonConvert.DeserializeObject<List<DiagnosticReport>>(result.Data.ToJsonStr());
                    return result;
                }
                catch (Exception ex)
                {
                    Utility.Logger.Error($"请求{api}错误,参数{json}，返回{responseStr}", ex);
                    return new MeasureDataAnalysisResponseDto() { Code = 1 };
                }
            }
        }

        /// <summary>
        /// 保存诊断报告数据
        /// </summary>
        /// <param name="query">项目编号</param>
        /// <param name="diagnosticReports">诊断结果文件</param>
        /// <returns></returns>
        public async Task<ApiResult> SaveDiagnosticReport(MsDiagnosticReportRequestDto query, List<DiagnosticReport> diagnosticReports)
        {
            if (string.IsNullOrWhiteSpace(query.ProjectNo))
            {
                throw new OperationException("项目编号不能为空");
            }
            // 拆分公司id和项目Id
            var projectNumberSplit = query.ProjectNo.Split("-");
            // 公司Id
            string compayNumber = projectNumberSplit[0];
            // 项目流水号
            string projectSeq = projectNumberSplit[1];
            var bucketName = "diagnostic-report";
            var modelList = new List<MsDiagnosticReport>();
            foreach (var item in diagnosticReports)
            {
                // 文件名
                string fileName = item.FileName.Split(@"/")[1];
                var objectName = $"{compayNumber}/{projectSeq}/{query.BuildingName}/{fileName}";
                // 对解析后的二进制字符串进行base64 解码
                byte[] fileBytes = Convert.FromBase64String(item.FileData);
                bool result = false;
                using (var stream = new MemoryStream(fileBytes))
                {
                    result = await MinioHelper.PutObjectAsync(bucketName, objectName, stream, stream.Length).ConfigureAwait(false);
                }
                if (!result)
                {
                    // 诊断报告保存失败，请稍后再试
                    return ApiResult.Error(Localizer["YB0466"].Value);
                }

                var addModel = new MsDiagnosticReport()
                {
                    Id = Guid.NewGuid(),
                    ProjectId = query.ProjectId,
                    ProjectNo = query.ProjectNo,
                    BuildingName = query.BuildingName,
                    BucketName = bucketName,
                    ObjectName = objectName,
                    CompanyId = OperatorProvider.Get().CompanyGuid,
                    ProjectStandardId = query.ProjectStandardId,
                    ProjectStandardName = query.ProjectStage,
                    FileName = query.FileName,
                    SaveDir = query.SaveDir,
                    FileServer = MinioHelper.EndPoint,
                    TaskType = query.TaskType,
                    TaskProperty = query.TaskProperty,
                    FloorName = query.FloorName
                };
                modelList.Add(addModel);
            }

            var reports = await MsDiagnosticReportRepository.GetMsDiagnosticReportData(query);
            if (reports != null && reports.Count > 0)
            {
                // 逻辑删除报告
                reports.ForEach(x => MsDiagnosticReportRepository.RemoveById(x.Id, true));
            }

            MsDiagnosticReportRepository.AddRange(modelList);
            await UnitOfWork.SaveChangesAsync();
            return ApiResult.Success().SetData(modelList);
        }

        /// <summary>
        /// 诊断QA接口
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public async Task<ApiResult> WxGetQualityAnalysisQA(WxQADto query)
        {
            #region 数据校验

            // 获取项目信息
            var project = await ProjectService.GetProjectInfo(query.ProjectId);
            if (project == null)
            {
                // 项目不存在
                throw new OperationException(Localizer["YB0064"].Value);
            }
            var buildingInfo = project.DetailsInfo.FirstOrDefault(
                x => x.Building == query.BuildingName);

            if (buildingInfo == null)
            {
                // 不存在的楼栋信息
                throw new OperationException(Localizer["YB0200"].Value);
            }
            if (!string.IsNullOrWhiteSpace(query.FloorName)
                && int.Parse(buildingInfo.Floor) < int.Parse(query.FloorName))
            {
                // 不存在的楼层信息
                throw new OperationException(Localizer["YB0467"].Value);
            }

            var projectStandard = await MsProjectStandardRepository.GetProjectStandardByName(
                OperatorProvider.Get().CompanyGuid, project.ProjectId, query.ProjectStage);

            if (projectStandard == null)
            {
                // 项目阶段不存在
                throw new OperationException(Localizer["YB0468"].Value);
            }

            #endregion 数据校验

            var msDiagnosticReportRequest = new MsDiagnosticReportRequestDto()
            {
                ProjectId = project.ProjectId,
                BuildingName = query.BuildingName,
                ProjectStage = query.ProjectStage,
                CompanyId = OperatorProvider.Get().CompanyGuid,
                FloorName = query.FloorName,
                ProjectStandardId = projectStandard.ProjectStandardId
            };

            var report = await MsDiagnosticReportRepository.GetMsDiagnosticReport(msDiagnosticReportRequest);
            if (report == null)
            {
                // 未查询到相关数据
                return ApiResult.Success(Localizer["YB0115"].Value);
            }

            var dto = new MeasureQADto()
            {
                FileName = report.FileName,
                SaveDir = report.SaveDir,
                Question = query.Question,
            };
            return ApiResult.Success().SetData(dto);
        }

        /// <summary>
        /// 诊断QA接口
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        private async Task<ApiResult> MeasureDataQA(MeasureQADto request)
        {
            string json = JsonConvert.SerializeObject(request);
            string api = baseUrl + $"getqa";
            var headers = new Dictionary<string, string>();
            string body = string.Format("qdata={0}", json);
            using (var response = await HttpUtility.PostAsync(api, body, timeOut, headers, "application/x-www-form-urlencoded"))
            {
                try
                {
                    var responseStr = await response.Content.ReadAsStringAsync();
                    var result = JsonConvert.DeserializeObject<MeasureDataQAResponseDto>(responseStr);
                    if (result.Code != 0)
                    {
                        Utility.Logger.Info($"request code:{responseStr}[{response.StatusCode}]");
                    }
                    return ApiResult.SetCode((AjaxCode)result.Code, result.Message);
                }
                catch (Exception ex)
                {
                    Utility.Logger.Error($"请求{api}错误！", ex);
                    return ApiResult.Error(ex.Message.ToString());
                }
            }
        }

        /// <summary>
        /// 获取用户相关的诊断报告
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public async Task<List<WxReportResponse>> WxGetUserReportData(WxReportDto query)
        {
            if (!string.IsNullOrWhiteSpace(query.ProjectName) && query.ProjectName.IsSpecialChars())
            {
                // 站点名称不能包含特殊字符
                throw new OperationException(Localizer["YB0090"].Value);
            }

            int top = 0;
            if (!int.TryParse(query.Top.ToString(), out top))
            {
                // {0}取值范围有误
                throw new OperationException(string.Format(Localizer["YB0469"].Value, "Top"));
            }

            #region 数据查询

            List<NpgsqlParameter> parameters = new List<NpgsqlParameter>
            {
                new NpgsqlParameter("@companyId",OperatorProvider.Get().CompanyGuid),

                new NpgsqlParameter("@top",query.Top)
            };

            var projectList = StatisService.GetRelationProjectsSql("T1", "ProjectId");

            string sql = string.Format(
                VisionCloudGlobalContext.GetSection("sqls:sql:query_wx_user_report_data"),
                projectList, query.ProjectName);

            #endregion 数据查询

            List<WxReportResponse> result = new List<WxReportResponse>();
            var reportList = await PgSqlHelper.QueryListAsync<MsDiagnosticReportDto>(sql, parameters.ToArray());
            foreach (var item in reportList)
            {
                string floorName = string.IsNullOrWhiteSpace(item.FloorName) ? string.Empty : $"-{item.FloorName}层";
                var model = new WxReportResponse()
                {
                    Id = item.FileName,
                    SaveDir = item.SaveDir,
                    ReportName = $"{item.ProjectName}-{item.BuildingName}栋{floorName}-{item.ProjectStandardName}-{item.TaskType.ToInt32()}-{item.TaskProperty.ToInt32()}",
                    CreatedDate = item.CreatedDate,
                    LastUpdatedDate = item.LastUpdatedDate,
                    ProjectStage = item.ProjectStandardName
                };
                result.Add(model);
            }
            return result;
        }

        /// <summary>
        /// 诊断报告文件URL
        /// </summary>
        /// <param name="relativePath"></param>
        /// <returns></returns>
        private string ToDiagnosticReportUrl(string relativePath)
        {
            string flag = "diagnostic-report";
            relativePath = relativePath.Replace(@"\", "/");
            int pIndex = relativePath.IndexOf(flag);
            if (pIndex > -1)
            {
                relativePath = relativePath.Substring(pIndex + flag.Length);
            }
            return $"{fileServer}/diagnosticreport/{relativePath}";
        }

        /// <summary>
        /// 获取常见问题列表
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public async Task<ApiResult> WxGetCommonMessages(WxMessageDto query)
        {
            if (query.Type < -1)
            {
                // 未查询到相关数据
                throw new OperationException(string.Format(Localizer["YB0469"].Value, "Type"));
            }
            var messages = await SysWxMessageRepository.GetSysWxMessageList(query);
            if (messages == null || messages.Count == 0)
            {
                // 未查询到相关数据
                return ApiResult.Success(Localizer["YB0115"].Value);
            }
            var result = new List<WxMessageResponseDto>();
            foreach (var item in messages)
            {
                result.Add(item.CopyTo<WxMessageResponseDto>());
            }

            return ApiResult.Success().SetData(result);
        }
    }
}